package com.dean.service.impl;

import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.exception.ExcelCommonException;
import com.dean.dao.DeanToolDao;
import com.dean.entity.DeanImportInfo;
import com.dean.entity.SysDbConnInfo;
import com.dean.exception.DeanRuntimeException;
import com.dean.utils.DeanJdbcUtils;
import com.dean.utils.DeanSqlUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class ExcelImpListner extends AnalysisEventListener<Map<Integer,String>> {
    private static final Logger logger = LoggerFactory.getLogger(ExcelImpListner.class);

    // 默认单次提交数据量为 1000;
    private static final Integer defaulCommitNum = 1000;

    private static final Integer defaultFetchSize = 1000;

    private Connection connection;

    private PreparedStatement ps;

    private DeanImportInfo importInfo;
    private SysDbConnInfo connectInfo;
    private List<Integer> head = new ArrayList<Integer>();
    private List<List<String>> datas = new ArrayList<List<String>>();
    private Integer counter = 0;
    private String insertSql;

    private ExcelImpListner(){}
    public ExcelImpListner(DeanImportInfo importInfo){
        this.importInfo = importInfo;
        this.insertSql = DeanSqlUtils.buildInsertSql(importInfo.getTableName(),importInfo.getFields(),importInfo.getFilePath(),importInfo.getSheetName());
    }

    @Override
    public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
        super.invokeHeadMap(headMap, context);
        if(context.readRowHolder().getRowIndex()+1 < importInfo.getSkipHead()){
            logger.info("跳过表头:{}",headMap);
            return;
        }
        Map<String,Integer> headMapCovert = new HashMap<String,Integer>(headMap.size());
        //将key value 反转
        headMap.forEach((key,val)->{
            headMapCovert.put(val.toUpperCase(),key);
        });
        head.clear();
        String[] fileds =importInfo.getFields();
        logger.info("用户指定表头:{}",fileds);
        logger.info("文件读取到表头{}:",headMap);
        for (String filed : fileds) {
            if(headMapCovert.containsKey(filed.toUpperCase()) && !filed.contains("=")){
                head.add(headMapCovert.get(filed.toUpperCase()));
            }
        }
        logger.info("用户指定表头与文件表头映射:{}",head);
        if(this.head.size()!=fileds.length) {
            throw new ExcelCommonException("ERROR-表头列匹配不成功");
        }
    }

    @Override
    public void invoke(Map<Integer, String> data, AnalysisContext analysisContext) {
        List<String> row = new ArrayList<String>();
        for (Integer integer : head) {
            row.add(data.get(integer));
        }
        datas.add(row);
        counter++;
        if(counter%importInfo.getCommitNums()==0){
            saveDB();
            datas.clear();
            logger.info("文件:{}sheetName:{}已导入{}条数据,导入完成时间:{}",importInfo.getFilePath(),importInfo.getSheetName(),counter, LocalDateTime.now());
        }
    }

    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
        if(counter%importInfo.getCommitNums() > 0){
            saveDB();
            logger.info("文件:{}sheetName:{}已导入{}条数据,导入完成时间:{}",importInfo.getFilePath(),importInfo.getSheetName(),counter, LocalDateTime.now());
        }
        datas.clear();
        this.connectInfo.setClose(true);
    }

    /**
     * 保存数据到数据库
     */
    private void saveDB(){
        try{
            if (connection == null) {
                this.connectInfo = DeanToolDao.getInstance().queryConnInfo(importInfo.getConnName());
                connection = DeanJdbcUtils.getConnection(connectInfo);
                connection.setAutoCommit(false);
                ps = DeanJdbcUtils.getPreparedStatement(connection, insertSql);
            }
            for (List<String> data : datas) {
                int size = data.size();
                for (int i = 0; i < size; i++) {
                    ps.setString(i + 1, data.get(i));
                }
                ps.addBatch();
            }
            ps.executeBatch();
            ps.clearBatch();
            connection.commit();
        } catch (ClassNotFoundException e) {
            logger.error(e.getMessage(),e);
            DeanRuntimeException.throwException(996,e.getMessage());
        } catch (SQLException throwables) {
            logger.error(throwables.getMessage(),throwables);
            try {
                connectInfo.setClose(true);
                connection.rollback();
            } catch (SQLException e) {
                logger.error(e.getMessage(),e);
            }
            DeanRuntimeException.throwException(996,throwables.getMessage());
        }finally {
            // 关闭连接
            if(connectInfo.getClose()){
                DeanJdbcUtils.close(ps,connection);
                connection = null;
            }
        }

    }

}